<template>
  <div class="tab-scroll" ref="tabScrollRef" @wheel.prevent="handleWheelScroll">
    <div
      class="tabbar-item"
      :class="['tab-item-' + tabbarMode, curTabName == item.name ? 'sv-tab-active' : '']"
      v-for="(item, index) in tabbarList"
      :key="item.name"
      @click="tapTab(item)"
      @contextmenu.prevent="handleContextMenu($event, item)"
    >
      <i v-if="isTabbarIcon && item.meta.icon" :class="item.meta.icon" class="tab-prefix-icon"></i>
      <span class="tab-title">{{ item.meta.title }}</span>
      <i v-if="item.meta.affix" class="sv-icon-pin tab-suffix-icon" @click.stop="unfixTab(item)"></i>
      <i v-else class="sv-icon-close tab-suffix-icon" @click.stop="closeTab(item)"></i>
    </div>
  </div>

  <!-- 更多菜单 -->
  <Teleport to="body">
    <div
      v-if="showMoreMenu"
      ref="moreMenuRef"
      class="more-menu"
      :style="{
        top: `${menuPosition.y}px`,
        left: `${menuPosition.x}px`,
      }"
    >
      <div class="more-menu-item cursor-pointer" @click="moreMenuCmd('刷新')">
        <i class="sv-icon-change more-menu-item-icon"></i>
        <span>刷新</span>
      </div>
      <div class="more-menu-item cursor-pointer" @click="moreMenuCmd('固定')">
        <i class="sv-icon-pin more-menu-item-icon"></i>
        <span>固定</span>
      </div>
      <div class="more-menu-item cursor-pointer" @click="moreMenuCmd('最大化')">
        <i class="sv-icon-fullscreen more-menu-item-icon"></i>
        <span>最大化</span>
      </div>
      <el-divider class="mtb-6" />
      <div class="more-menu-item cursor-pointer" @click="moreMenuCmd('关闭当前')">
        <i class="sv-icon-close more-menu-item-icon"></i>
        <span>关闭当前</span>
      </div>
      <div class="more-menu-item cursor-pointer" @click="moreMenuCmd('关闭左侧')">
        <i class="sv-icon-left-arrow more-menu-item-icon"></i>
        <span>关闭左侧</span>
      </div>
      <div class="more-menu-item cursor-pointer" @click="moreMenuCmd('关闭右侧')">
        <i class="sv-icon-right-arrow more-menu-item-icon"></i>
        <span>关闭右侧</span>
      </div>
      <div class="more-menu-item cursor-pointer" @click="moreMenuCmd('关闭其他')">
        <i class="sv-icon-reduce-btn more-menu-item-icon"></i>
        <span>关闭其他</span>
      </div>
      <div class="more-menu-item cursor-pointer" @click="moreMenuCmd('关闭全部')">
        <i class="sv-icon-error more-menu-item-icon"></i>
        <span>关闭全部</span>
      </div>
    </div>
  </Teleport>
</template>

<script setup>
import { nextTick, onMounted, onUnmounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { storeToRefs } from 'pinia'
import { useDraggable } from 'vue-draggable-plus'
import { useMenuStore } from '@/stores/menu'
import { useTabbar } from '@/hooks/useTabbar'
import { useThemeStore } from '@/stores/theme'

const emits = defineEmits(['change'])

const route = useRoute()
const router = useRouter()

const themeStroe = useThemeStore()
const { isTabbarIcon, tabbarMode } = storeToRefs(themeStroe)

const menuStroe = useMenuStore()
const { tabbarList } = storeToRefs(menuStroe)

const tabScrollRef = ref()
const curTabName = ref('')
const hoverTab = ref({})

// 初始化标签
useTabbar().initTabs()

/**
 * 拖拽实例对象
 * @description 包含了一些方法，比如 start、destroy、pause 等
 * @see https://vue-draggable-plus.pages.dev/
 * @returns {Object} draggable
 */
const draggable = useDraggable(tabScrollRef, tabbarList, {
  animation: 150,
  onStart() {
    console.log('start')
  },
  onUpdate() {
    console.log('update')
  },
})

watch(
  () => route.fullPath,
  (newVal) => {
    if (!route.meta.layouts) return // 不走布局的路由不做标签和缓存处理
    curTabName.value = route.name

    // 简化tab对象
    const tab = {
      name: route.name,
      path: route.path,
      meta: route.meta,
    }

    emits('change', tab)

    useTabbar().addTab(tab)

    activeTabScrollIntoView()
  },
  {
    immediate: true,
  }
)

onMounted(() => {
  activeTabScrollIntoView()
})

function tapTab(tab) {
  curTabName.value = tab.name
  router.push(tab.path)
}

function unfixTab(tab) {
  useTabbar().unfixTab(tab)
}

function closeTab(tab) {
  useTabbar().closeTab(tab)
}

// 处理鼠标滚轮滚动
function handleWheelScroll(event) {
  // 滑动时关闭右键菜单
  closeContextMenu()

  if (!tabScrollRef.value) return

  // 获取滚轮滚动的距离
  const delta = event.deltaY || event.detail || event.wheelDelta

  // 设置滚动速度系数
  const scrollSpeed = 2

  // 计算新的滚动位置
  const newScrollLeft = tabScrollRef.value.scrollLeft + delta * scrollSpeed

  // 使用平滑滚动效果
  tabScrollRef.value.scrollTo({
    left: newScrollLeft,
    behavior: 'smooth',
  })
}

/**
 * 当前选项卡active-tab移动至视口可见范围
 * @see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/scrollIntoView
 */
function activeTabScrollIntoView() {
  nextTick(() => {
    const activeTab = document.querySelector('.sv-tab-active')
    activeTab.scrollIntoView({
      behavior: 'smooth',
    })
  })
}

const moreMenuRef = ref()
const showMoreMenu = ref(false)
const menuPosition = ref({ x: 0, y: 0 })

// 处理容器右键菜单
function handleContextMenu(event, tab) {
  showMoreMenu.value = true

  // 确保菜单位置不会超出屏幕
  adjustMenuPosition(event.pageX, event.pageY)

  hoverTab.value = tab
}

function closeContextMenu() {
  showMoreMenu.value = false
}

// 点击页面其他区域关闭右键菜单
function handleDocumentClick(event) {
  if (!showMoreMenu.value) return

  // ref挂在component上时，从$el中获取节点内置方法，ref直接挂载普通标签上时可直接获取内置方法
  if (moreMenuRef.value && !moreMenuRef.value?.contains(event.target)) {
    closeContextMenu()
  }
}

// 调整菜单位置，确保不会超出屏幕
function adjustMenuPosition(x, y) {
  // 使用nextTick确保DOM已更新
  nextTick(() => {
    if (!moreMenuRef.value) return

    const menuWidth = moreMenuRef.value.offsetWidth
    const menuHeight = moreMenuRef.value.offsetHeight
    const windowWidth = window.innerWidth
    const windowHeight = window.innerHeight

    // 调整X坐标，确保菜单不会超出屏幕右侧
    let adjustedX = x
    if (x + menuWidth > windowWidth) {
      adjustedX = windowWidth - menuWidth - 10
    }

    // 调整Y坐标，确保菜单不会超出屏幕底部
    let adjustedY = y
    if (y + menuHeight > windowHeight) {
      adjustedY = windowHeight - menuHeight - 10
    }

    menuPosition.value = {
      x: Math.max(10, adjustedX), // 确保不会太靠近屏幕左侧
      y: Math.max(10, adjustedY), // 确保不会太靠近屏幕顶部
    }
  })
}

/**
 * 菜单面板指令方法
 * @param {String} cmd 指令
 */
function moreMenuCmd(cmd) {
  switch (cmd) {
    case '刷新':
      useTabbar().refreshCurrentPage(hoverTab.value)
      break
    case '固定':
      useTabbar().affixTab(hoverTab.value)
      break
    case '最大化':
      useTabbar().maximizeCurrentPage(hoverTab.value)
      break
    case '关闭当前':
      useTabbar().closeTab(hoverTab.value)
      break
    case '关闭左侧':
      useTabbar().closeLeftTabs(hoverTab.value)
      break
    case '关闭右侧':
      useTabbar().closeRightTabs(hoverTab.value)
      break
    case '关闭其他':
      useTabbar().closeOtherTabs(hoverTab.value)
      break
    case '关闭全部':
      useTabbar().closeAllTabs()
      break
  }
  closeContextMenu()
}

// 组件挂载时添加全局事件监听
onMounted(() => {
  document.addEventListener('click', handleDocumentClick)
})

// 组件卸载时清理事件监听
onUnmounted(() => {
  document.removeEventListener('click', handleDocumentClick)
})
</script>

<style lang="scss" scoped>
.tab-scroll {
  height: 100%;
  display: flex;
  align-items: center;
  flex: 1;
  white-space: nowrap;
  overflow-x: auto;
  overflow-y: hidden;

  // 隐藏默认滚动条
  &::-webkit-scrollbar {
    display: none;
  }

  .tabbar-item {
    display: flex;
    align-items: center;
    position: relative;

    .tab-title {
      font-size: 14px;
    }

    .tab-prefix-icon {
      margin-right: 6px;
      font-size: 16px;
      margin-top: 1px;
    }

    .tab-suffix-icon {
      padding: 2px;
      margin-left: 2px;
      margin-top: 3px;
      font-size: 14px;
      transition: all 0.3s ease-in-out;

      &:hover {
        color: #ffffff;
        background-color: var(--color-primary-gradient-6);
        border-radius: 50%;
      }
    }
  }

  .tab-item-plain {
    height: 100%;
    padding: 0 10px;
    cursor: pointer;
    border-right: 1px solid var(--border-color);

    &:hover {
      background-color: var(--color-primary-gradient-9);
    }

    &.sv-tab-active {
      background-color: var(--color-primary-gradient-8);

      &::after {
        content: '';
        position: absolute;
        left: 0;
        bottom: 0;
        height: 1px;
        width: 100%;
        background-color: var(--color-primary);
      }
    }
  }
}

.more-menu {
  position: fixed;
  border: 1px solid var(--border-color);
  background-color: var(--bg-color);
  border-radius: var(--base-radius);
  padding: 5px 10px;
  font-size: 14px;
  user-select: none;

  .more-menu-item {
    height: 24px;
    display: flex;
    align-items: center;

    &:hover {
      color: var(--color-primary);
    }

    .more-menu-item-icon {
      font-size: 12px;
      margin-right: 4px;
    }
  }
}
</style>
